/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019.
 * Description: support preempt off feature
 * Author: chenshiyan
 * Create: 2019-5-8
 */
#include <linux/printk.h>
#include <linux/utsname.h>
#ifdef CONFIG_PPC32
#include <asm/code-patching.h>
#endif
#include <linux/rtos_preempt_off.h>

int preempt_status = PREEMPT_ON;

static void __init rename_uts_version(void)
{
	const char preempt_str[] = "PREEMPT";
	const char preempt_off_str[] = "PREEMPT(OFF)";
	const char off_str[] = "(OFF)";
	char *uts_version_str = (char *)&init_uts_ns.name.version;
	char tmp_str[__NEW_UTS_LEN + 1];
	char *preempt_addr = NULL;

	/* change 'PREEMPT' to 'PREEMPT(OFF)' or just delete in 'uname -a' */
	preempt_addr = strstr(uts_version_str, preempt_str);
	if (!preempt_addr) {
		pr_err("preempt_off: rename uts version failed\n");
		return;
	}
	if ((strlen(uts_version_str) + strlen(off_str)) < __NEW_UTS_LEN) {
		strcpy(tmp_str, (preempt_addr + strlen(preempt_str)));
		strcpy(preempt_addr, preempt_off_str);
		strcpy(preempt_addr + strlen(preempt_off_str), tmp_str);
	} else {
		strcpy(preempt_addr, (preempt_addr + strlen(preempt_str)));
	}
}

static int __init preempt_off_setup(char *str)
{
	preempt_status = PREEMPT_OFF;
	rename_uts_version();
#ifdef CONFIG_PPC32
	patch_instruction_site(&patch__kernel_preempt_off, ppc_inst(PPC_INST_NOP));
#endif

	pr_info("preempt_off: disable kernel preempt\n");

	return 0;
}
__setup("preempt_off", preempt_off_setup);

